package cn.yuanqiao.archive.uploadfile.service.impl;

import cn.yuanqiao.archive.appManager.service.ITenantSysConfigService;
import cn.yuanqiao.archive.fondsFolder.domain.Model;
import cn.yuanqiao.archive.fondsFolder.mapper.FondsFolderMapper;
import cn.yuanqiao.archive.uploadfile.annotation.UploadMode;
import cn.yuanqiao.archive.uploadfile.constant.FileConstant;
import cn.yuanqiao.archive.uploadfile.dto.FileUploadDTO;
import cn.yuanqiao.archive.uploadfile.dto.FileUploadRequestDTO;
import cn.yuanqiao.archive.uploadfile.dto.ModelUploadDTO;
import cn.yuanqiao.archive.uploadfile.dto.PackageUploadDTO;
import cn.yuanqiao.archive.uploadfile.enums.UploadModeEnum;
import cn.yuanqiao.archive.uploadfile.service.SliceUploadStrategy;
import cn.yuanqiao.archive.webservice.service.impl.ArchiveWebServiceImpl;
import cn.yuanqiao.archive.webservice.utils.WebServiceFileUtils;
import cn.yuanqiao.common.exception.ServiceException;
import cn.yuanqiao.common.utils.DateUtils;
import cn.yuanqiao.common.utils.StringUtils;
import cn.yuanqiao.common.utils.SecurityUtils;
import com.alibaba.fastjson2.JSONObject;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;

import java.io.*;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class FileService {
    private static final Logger log = LoggerFactory.getLogger(FileService.class);

    private Map<UploadModeEnum, SliceUploadStrategy> sliceUploadStrategyMap;
    @Autowired
    private ITenantSysConfigService sysConfigService;
    @Autowired
    private FondsFolderMapper fondsFolderMapper;
    @Autowired
    private ArchiveWebServiceImpl archiveWebService;

    @Value("${onLineArchive.Path}")
    private String onLineArchivePath;

    @Autowired
    public void setSliceUploadStrategyMap(List<SliceUploadStrategy> strategyList){
        sliceUploadStrategyMap=strategyList.stream().collect(Collectors.toMap(strategy->
                        AnnotationUtils.findAnnotation(strategy.getClass(), UploadMode.class).mode(),
                v->v,(v1,v2)->v1
        ));
    }

    public FileUploadDTO fileUpload(FileUploadRequestDTO fileUploadRequestDTO){
        //获取zip包上传路径
        String articulated_path = sysConfigService.selectConfigByKey("ARTICULATED_PATH");
        if(!StringUtils.isNotEmpty(articulated_path)){
            articulated_path = "/data/guajiezip";
        }
        fileUploadRequestDTO.setPath(articulated_path);

        SliceUploadStrategy sliceUploadStrategy = sliceUploadStrategyMap.get(fileUploadRequestDTO.getModeEnum());
        FileUploadDTO fileUploadDTO = sliceUploadStrategy.sliceUpload(fileUploadRequestDTO);
        //Map<Integer, String> chunkMd5Info = fileUploadDTO.getChunkMd5Info();
        String zipPath = fileUploadDTO.getPath();
        //log.info("压缩包路径：：：{}",zipPath);
        if(StringUtils.isNotEmpty(zipPath)){
            String path = fileUploadRequestDTO.getPath();
            //String zipPath = fileUploadDTO.getPath();
            String unZipCharSet = fileUploadRequestDTO.getUnZipCharSet();
            if(!StringUtils.isNotEmpty(unZipCharSet)) unZipCharSet = "GBK";
            String unZipPath = path + FileConstant.FILE_SEPARATORCHAR+fileUploadRequestDTO.getMd5()+FileConstant.FILE_SEPARATORCHAR;
            //解压
            //ZipUtils.unZip(new File(zipPath),unZipPath,unZipCharSet);
            log.info("解压zip编码：：：{}",unZipCharSet);
            decompress(zipPath,unZipPath,unZipCharSet);
            List<Map<String,String>> list = new ArrayList<>();
            //遍历获取文件信息
            copyFiles(new File(unZipPath),list);
            fileUploadDTO.setUnZipPath(unZipPath);
            fileUploadDTO.setFileInfos(list);
        }
        return fileUploadDTO;
    }

    public FileUploadDTO packageFileUpload(PackageUploadDTO fileUploadRequestDTO) {
        String msg = "";
        String categoryId = fileUploadRequestDTO.getCategoryId();
        String tenantCode = SecurityUtils.getTenantCode();
        String md5 = fileUploadRequestDTO.getMd5();
        if(StringUtils.isEmpty(onLineArchivePath)){
            throw new ServiceException("移交包路径未配置");
        }
        if(!onLineArchivePath.endsWith("/")){
            onLineArchivePath+="/";
        }
        fileUploadRequestDTO.setPath(onLineArchivePath+md5);

        SliceUploadStrategy sliceUploadStrategy = sliceUploadStrategyMap.get(fileUploadRequestDTO.getModeEnum());
        FileUploadDTO fileUploadDTO = sliceUploadStrategy.sliceUpload(fileUploadRequestDTO);
        //Map<Integer, String> chunkMd5Info = fileUploadDTO.getChunkMd5Info();
        String zipPath = fileUploadDTO.getPath();
        //log.info("压缩包路径：：：{}",zipPath);
        if(StringUtils.isNotEmpty(zipPath)){
            String path = fileUploadRequestDTO.getPath();
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("categoryId",categoryId);
            jsonObject.put("tenantCode",tenantCode);
            String jsonStr = jsonObject.toString();
            log.info("jsonStr：：："+jsonStr);
            String jsonBase64 = Base64Utils.encodeToString(jsonStr.getBytes());
            try {
                String md5Str = WebServiceFileUtils.getFileMD5(new File(zipPath));  //获取文件MD5
                String fileBase64 = WebServiceFileUtils.fileToBase64(new File(zipPath));
                msg = archiveWebService.saveArchive(jsonBase64, md5Str, fileBase64);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            if(!"".equals(msg)){
                JSONObject jsonObject1 = JSONObject.parseObject(msg);
                String code = jsonObject1.getString("code");
                String msg1 = jsonObject1.getString("msg");
                if(!"200".equals(code)){
                    throw new ServiceException(msg1);
                }else{
                    FileUtils.deleteQuietly(new File(path));//删除文件
                }
            }
        }
        return fileUploadDTO;
    }

    public FileUploadDTO modelFileUpload(ModelUploadDTO fileUploadRequestDTO){
        //获取zip包上传路径
        String modelUploadPath = sysConfigService.selectConfigByKey("YQ_MNT");
        if(!StringUtils.isNotEmpty(modelUploadPath)){
            modelUploadPath = "/data/modelUpload";
        }
        String prefixPath = modelUploadPath;
        Integer type = fileUploadRequestDTO.getType();
        if(!modelUploadPath.endsWith("/")) modelUploadPath+="/";
        if(type==1) modelUploadPath+="dashiji";  //大事记
        if(type==2) modelUploadPath+="zuzhiyange";  //组织沿革

        fileUploadRequestDTO.setPath(modelUploadPath);
        SliceUploadStrategy sliceUploadStrategy = sliceUploadStrategyMap.get(fileUploadRequestDTO.getModeEnum());
        FileUploadDTO fileUploadDTO = sliceUploadStrategy.sliceUpload(fileUploadRequestDTO);
        String path = fileUploadDTO.getPath();
        if(StringUtils.isNotEmpty(path)){
            /**
             * 若name取不到 则需要前端传
             */
            String name = fileUploadRequestDTO.getFile().getOriginalFilename();
            String name2 = name;
            int i1 = name.lastIndexOf(".");
            String suff = name.substring(i1);
            String pre = name.substring(0,i1-13);
            name = pre + suff;
            Model model = new Model();
            if(!"undefined".equals(fileUploadRequestDTO.getMj())){
                model.setMj(fileUploadRequestDTO.getMj());
            }
            model.setFileName(name);
            model.setIsDel(0);
            model.setUserId(SecurityUtils.getUserId());
            model.setDeptId(SecurityUtils.getLoginUser().getUser().getDeptId());
            model.setPrefix(prefixPath);
            model.setPath(type==1?"dashiji/"+name2:type==2?"zuzhiyange/"+name2:"");
            model.setType(type);
            model.setCreateTime(DateUtils.getNowDate());
            model.setCreateBy(SecurityUtils.getUsername());
            fondsFolderMapper.insertModel(model);
        }
        return fileUploadDTO;
    }

    public static void decompress(String zipFilePath, String descDir,String charset) {
        File zipFile = new File(zipFilePath);
        File pathFile = new File(descDir);
        if (!pathFile.exists()) {
            pathFile.mkdirs();
        }
        log.info("{}  开始解压...", zipFilePath);
        try (ZipFile zip = new ZipFile(zipFile,charset)) {
            Enumeration<ZipArchiveEntry> entries = zip.getEntries();
            while (entries.hasMoreElements()) {
                // 遍历获取压缩文件内全部条目，包括子条目中的条目
                ZipArchiveEntry entry = entries.nextElement();
                String entryName = entry.getName();
                try (InputStream in = zip.getInputStream(entry)) {
                    String outPath = (descDir + "/" + entryName);
                    // 判断路径是否存在，不存在则创建文件路径
                    File file = new File(outPath.substring(0, outPath.lastIndexOf('/')));
                    if (!file.exists()) {
                        file.mkdirs();
                    }                // 判断文件全路径是否为文件夹,如果是上面已经创建,不需要解压
                    if (new File(outPath).isDirectory()) {
                        continue;
                    }
                    try (OutputStream out = new FileOutputStream(outPath)) {
                        byte[] buf = new byte[4 * 1024];
                        int len = 0;
                        while ((len = in.read(buf)) >= 0) {
                            out.write(buf, 0, len);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                        throw new ServiceException("解压失败");
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    throw new ServiceException("解压失败");
                }
            }
            log.info("{}  解压完毕...", zipFilePath);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("解压失败");
        }
    }

    public void copyFiles(File srcFile,List<Map<String,String>> list){
        //	List<Map<String,String>> lm = new ArrayList<Map<String,String>>();
        Map<String,String> m = null;
        File[] tmp = srcFile.listFiles();
        for (int i = 0; i < tmp.length; i++) {
            if (tmp[i].isFile()) {
                m = new HashMap<String,String>();
                String fileName = "";
					/*try {
						fileName = new String(tmp[i].getName().getBytes("ISO8859-1"),"GBK");
					} catch (UnsupportedEncodingException e) {
						fileName = tmp[i].getName();
					}*/
                fileName = tmp[i].getName();
                //log.debug("fileName=="+fileName);
                long fileSize = tmp[i].length();
                String fileType = fileName.substring(fileName.lastIndexOf(".")+1);
                String fileSizeStr = "";
                if (fileSize > 1024 * 1024){
                    fileSizeStr = (Math.round(fileSize * 100 / (1024 * 1024)) / 100) + "MB";
                }else{
                    fileSizeStr = (Math.round(fileSize * 100 / 1024) / 100) + "KB";
                }
                m.put("fileName", fileName);
                m.put("fileSize", fileSizeStr);
                m.put("fileType", fileType);
                list.add(m);
                //	return copyFiles(tmp[i], map);
            }
            if (tmp[i].isDirectory()) {
                String name = tmp[i].getName();
                if (tmp[i].listFiles().length != 0) {// 若不是空目录，则递归添加其下的目录和文件
                    copyFiles(tmp[i],list);
                }
            }
        }
    }
}
